/*
 * @Author: LiYu
 * @Date: 2022-04-03 20:58:59
 * @LastEditors: LiYu
 * @LastEditTime: 2022-04-03 23:04:44
 * @Description: 蛇类
 */
import { STAGE_W, SNAKE_W } from "../constants";
class Snake {
  // 蛇头
  head: HTMLElement;
  // 蛇体
  bodies: HTMLCollection;
  // 蛇容器
  snakeEl: HTMLElement;

  constructor() {
    this.snakeEl = document.querySelector('.snake')!;
    this.head = document.querySelector('.snake>.block')!;
    this.bodies = document.querySelector('.snake')!.getElementsByClassName('block');
  }

  get x() {
    return this.head.offsetLeft;
  }

  get y() {
    return this.head.offsetTop;
  }

  set x(value: number) {
    // 没变化不操作dom属性
    if(this.x === value) return;
    // 蛇撞墙
    if (value < 0 || value > STAGE_W - SNAKE_W) {
      throw new Error('蛇撞墙了！');
    }
    // 如果蛇头和第二节x相同，则代表在水平方向调头
    if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft  === value) {
      console.log('发生了水平方向调头');
      // 修正方向
      if(this.x > value) {
        value = this.x + SNAKE_W;
      } else {
        value = this.x - SNAKE_W;
      }
    }
    this.moveBody();
    this.head.style.left = `${value}px`;
    if(this.checkHeadBody()) {
      throw new Error('蛇撞到自己了！');
    }
  }

  set y(value: number) {
    // 没变化不操作dom属性
    if(this.y === value) return;
    // 蛇撞墙
    if (value < 0 || value > STAGE_W - SNAKE_W) {
      throw new Error('蛇撞墙了！');
    }
    // 如果蛇头和第二节y相同，则代表在垂直方向调头
    if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop  === value) {
      console.log('发生了垂直方向调头');
      // 修正方向
      if(this.y > value) {
        value = this.y + SNAKE_W;
      } else {
        value = this.y - SNAKE_W;
      }
    }
    this.moveBody();
    this.head.style.top = `${value}px`;
    if(this.checkHeadBody()) {
      throw new Error('蛇撞到自己了！');
    }
  }

  // 添加一节
  addBody() {
    const blockEl = document.createElement('div');
    blockEl.classList.add('block');
    this.snakeEl.insertAdjacentElement('beforeend', blockEl);
  }

  moveBody() {
    for(let i = this.bodies.length - 1; i > 0; i--) {
      let x = (this.bodies[i - 1] as HTMLElement).offsetLeft;
      let y = (this.bodies[i - 1] as HTMLElement).offsetTop;
      (this.bodies[i] as HTMLElement).style.left = `${x}px`;
      (this.bodies[i] as HTMLElement).style.top = `${y}px`;
    }
  }

  checkHeadBody():boolean {
    for(let i = 3, len = this.bodies.length; i < len; i ++) {
      const bd = this.bodies[i] as HTMLElement;
      // 存在与头相同坐标的身体块，则代表撞到自己身体了
      if(bd.offsetLeft === this.x && bd.offsetTop === this.y) {
        return true;
      }
    }
    return false;
  }
}

export default Snake;

